package org.budo.dubbo.protocol.http.page;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.budo.dubbo.protocol.http.page.util.InterfaceStructureUtil;
import org.budo.support.freemarker.FreemarkerUtil;
import org.budo.support.java.net.util.UrlEncodeUtil;
import org.budo.support.lang.util.IoUtil;
import org.budo.support.spring.io.util.ResourceUtil;
import org.budo.time.Time;
import org.springframework.core.io.ClassPathResource;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.common.utils.StringUtils;

/**
 * @author lmw
 */
public class PageDispatcher extends AbstractPage {
    private static final long serialVersionUID = 4927556141672295307L;

    private IndexPage indexPageServlet = new IndexPage();

    private InterfacePage interfacePageServlet = new InterfacePage();

    private FunctionPage functionPageServlet = new FunctionPage();

    private TypeStructurePage typeStructurePageServlet = new TypeStructurePage();

    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String interfaceName = request.getParameter("interface");
        String functionName = request.getParameter("function");
        String action = request.getParameter("action");

        if ("javascript-sdk".equals(action)) {
            this.renderJavascriptSdkPage(request, response);
            return;
        }
        if ("typescript-sdk".equals(action)) {
            this.renderTypescriptSdkPage(request, response);
            return;
        }
        if ("typescript-sdk-download".equals(action)) {
            this.renderTypescriptSdkDownload(request, response);
            return;
        }
        if ("java-sdk".equals(action)) {
            this.renderJavaSdkPage(request, response);
            return;
        }
        if ("objectivec-sdk".equals(action)) {
            this.renderObjectivecSdkPage(request, response);
            return;
        }
        if ("cpp-sdk".equals(action)) {
            this.renderCppSdkPage(request, response);
            return;
        }
        if ("cpp-sdk-download".equals(action)) {
            this.renderCppSdkDownload(request, response);
            return;
        }
        if ("objectivec-sdk-download".equals(action)) {
            this.renderObjectivecSdkDownload(request, response);
            return;
        }
        if ("api-doc".equals(action)) {
            this.renderApiDocDownload(request, response);
            return;
        }
        if ("api-md".equals(action)) {
            this.renderApiMdDownload(request, response);
            return;
        }
        if ("javascript-sdk-download".equals(action)) {
            this.renderJavascriptSdkDownload(request, response);
            return;
        }
        if ("javascript-sdk-dts-download".equals(action)) {
            this.renderJavascriptSdkDtsDownload(request, response);
            return;
        }
        if ("java-sdk-src-download".equals(action)) {
            this.renderJavaSdkSrcDownload(request, response);
            return;
        }
        if ("sign_check".equals(action)) {
            this.renderSignCheckPage(request, response);
            return;
        }
        if ("type_structure".equals(action)) {
            typeStructurePageServlet.service(request, response);
            return;
        }

        if (StringUtils.isEmpty(interfaceName)) {
            indexPageServlet.service(request, response);
            return;
        }
        if (StringUtils.isEmpty(functionName)) {
            interfacePageServlet.service(request, response);
            return;
        }

        functionPageServlet.service(request, response);
    }

    private void renderApiMdDownload(HttpServletRequest request, HttpServletResponse response) {
        response.setHeader("Content-Disposition", "attachment; filename = " + UrlEncodeUtil.encode("接口文档（Markdown）.md"));
    }

    private void renderApiDocDownload(HttpServletRequest request, HttpServletResponse response) {
        response.setHeader("Content-Disposition", "attachment; filename = " + UrlEncodeUtil.encode("接口文档（Word）.doc"));
    }

    private void renderTypescriptSdkDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("application/x-javascript");
        Map<String, Object> dataMap = CollectionUtils.toMap("interfaces", InterfaceStructureUtil.listInterfaceMap(Scope.Public));

        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/typescript-sdk-download.htm");
        this.renderPage(templateInput, dataMap, request, response);
    }

    private void renderJavascriptSdkDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Scope scope = this.getScope(request);

        String expires_in = request.getParameter("expires_in"); // 浏览器缓存时间
        Integer expiresIn = StringUtils.isEmpty(expires_in) ? 5 * 60 : new Integer(expires_in);

        response.setHeader("Cache-Control", "public"); // Cache-Control来控制页面的缓存与否,public:浏览器和缓存服务器都可以缓存页面信息；
        response.setHeader("Pragma", "Pragma"); // Pragma:设置页面是否缓存，为Pragma则缓存，no-cache则不缓存

        Long nowTime = Time.now().toMilliSeconds();
        response.setDateHeader("Last-Modified", nowTime); // Last-Modified:页面的最后生成时间
        response.setDateHeader("Expires", nowTime + (expiresIn * 1000)); // Expires:过时期限值

        response.setContentType("application/x-javascript");
        Map<String, Object> dataMap = CollectionUtils.toMap("interfaces", InterfaceStructureUtil.listInterfaceMap(scope));

        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/javascript-sdk-download.htm");
        this.renderPage(templateInput, dataMap, request, response);
    }

    private void renderTypescriptSdkPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, Object> dataMap = CollectionUtils.toMap("interfaces", InterfaceStructureUtil.listInterfaceMap(Scope.Public));

        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/typescript-sdk.htm");
        this.renderPage(templateInput, dataMap, request, response);
    }

    private void renderObjectivecSdkDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, Object> dataMap = CollectionUtils.toMap("interfaces", InterfaceStructureUtil.listInterfaceMap(Scope.Public));

        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/objectivec-sdk-download.htm");
        this.renderPage(templateInput, dataMap, request, response);
    }

    private void renderCppSdkDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, Object> dataMap = CollectionUtils.toMap("interfaces", InterfaceStructureUtil.listInterfaceMap(Scope.Public));

        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/cpp-sdk-download.htm");
        this.renderPage(templateInput, dataMap, request, response);
    }

    private void renderJavascriptSdkDtsDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("application/x-javascript");
        Map<String, Object> dataMap = CollectionUtils.toMap("interfaces", InterfaceStructureUtil.listInterfaceMap(Scope.Public));

        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/javascript-sdk-dts-download.htm");
        this.renderPage(templateInput, dataMap, request, response);
    }

    private void renderJavascriptSdkPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, Object> dataMap = CollectionUtils.toMap("interfaces", InterfaceStructureUtil.listInterfaceMap(Scope.Public));

        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/javascript-sdk.htm");
        this.renderPage(templateInput, dataMap, request, response);
    }

    private String renderJavaSdkCode(HttpServletRequest request) throws IOException {
        String sdk_package = request.getParameter("sdk_package");
        if (StringUtils.isEmpty(sdk_package)) {
            sdk_package = "sdk.pkg";
        }

        String sdk_type = request.getParameter("sdk_type");
        if (StringUtils.isEmpty(sdk_type)) {
            sdk_type = "SdkType";
        }

        Object dataMap = CollectionUtils.toMap("interfaces", InterfaceStructureUtil.listInterfaceMap(this.getScope(request)), //
                "sdk_package", sdk_package, //
                "sdk_type", sdk_type);
        InputStream templateInputStream = new ClassPathResource("api-doc-template/java-sdk-download.htm").getInputStream();

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        FreemarkerUtil.freemarkerRender(templateInputStream, dataMap, byteArrayOutputStream);
        return new String(byteArrayOutputStream.toByteArray());
    }

    private void renderJavaSdkPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, Object> dataMap = CollectionUtils.toMap();

        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/java-sdk.htm");
        this.renderPage(templateInput, dataMap, request, response);
    }

    private void renderCppSdkPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, Object> dataMap = CollectionUtils.toMap();

        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/cpp-sdk.htm");
        this.renderPage(templateInput, dataMap, request, response);
    }

    private void renderObjectivecSdkPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, Object> dataMap = CollectionUtils.toMap();

        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/objectivec-sdk.htm");
        this.renderPage(templateInput, dataMap, request, response);
    }

    private void renderJavaSdkSrcDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/plain");

        String code = this.renderJavaSdkCode(request);
        IoUtil.write(new ByteArrayInputStream(code.getBytes()), response.getOutputStream());
    }

    private void renderSignCheckPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String templateInput = ResourceUtil.classPathResourceInputStreamToString("api-doc-template/sign-check.htm");
        this.renderPage(templateInput, new HashMap<String, Object>(), request, response);
    }
}
